package demo2

import (
	"fmt"
	"math"
)

// Vec2 记录
type Vec2 struct {
	X, Y float32
}

// 加
func (v Vec2) add(other Vec2) Vec2 {
	return Vec2{
		v.X + other.X,
		v.Y + other.Y,
	}
}

// 减
func (v Vec2) sub(other Vec2) Vec2 {
	return Vec2{
		v.X - other.X,
		v.Y - other.Y,
	}
}

// 乘法
func (v Vec2) scale(s float32) Vec2 {
	return Vec2{v.X * s, v.Y * s}
}

// 距离
func (v Vec2) distanceTo(other Vec2) float32 {
	dx := v.X - other.X
	dy := v.Y - other.Y

	return float32(math.Sqrt(float64(dx*dx + dy*dy)))
}

// 插值
func (v Vec2) normalize() Vec2 {
	mag := v.X*v.X + v.Y*v.Y
	if mag > 0 {
		oneOverMag := 1 / float32(math.Sqrt(float64(mag)))
		return Vec2{v.X * oneOverMag, v.Y * oneOverMag}
	}

	return Vec2{0, 0}
}

// Player1 玩家
type Player1 struct {
	currPos   Vec2    // 当前位置
	targetPos Vec2    // 目标位置
	speed     float32 // 移动速度
}

// 移动到某个点就死设置目标位置
func (p *Player1) moveTo(v Vec2) {
	p.targetPos = v
}

// 获取当前位置
func (p *Player1) pos() Vec2 {
	return p.currPos
}

// 是否到达
func (p *Player1) isArrived() bool {
	// 通过计算当前玩家位置与目标位置的距离不超过移动的步长，判断已经到达目标点
	ret := p.currPos.distanceTo(p.targetPos)
	return ret < p.speed
}

// 逻辑更新
func (p *Player1) update() {
	if !p.isArrived() {
		// 计算单签位置指向目标的朝向
		dis := p.targetPos.sub(p.currPos).normalize()

		// 添加速度矢量生成新的位置
		newPos := p.currPos.add(dis.scale(p.speed))

		// 移动完成后，更新当前位置
		p.currPos = newPos
	}
}

// 创建新玩家
func newPlayer(speed float32) *Player1 {
	return &Player1{
		speed: speed,
	}
}

// TestDemo212 模拟二维矢量模拟玩家移动
func TestDemo212() {
	// 实例化玩家，初始化速速为 0.5
	player1 := newPlayer(0.5)

	fmt.Println(player1)

	// 玩家移动到 3， 1
	player1.moveTo(Vec2{3, 1})

	fmt.Println(player1)
	// 如果没有到达就一直循环
	for !player1.isArrived() {
		fmt.Println("开始移动")
		// 更新玩家位置
		player1.update()

		// 打印每次移动后的位置
		fmt.Println(player1.pos())
	}
}
